package top.cyuw.simplerpc.serialize.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import top.cyuw.simplerpc.exception.SerializeException;
import top.cyuw.simplerpc.dto.RpcRequest;
import top.cyuw.simplerpc.dto.RpcResponse;
import top.cyuw.simplerpc.serialize.Serializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @author chen
 * @date 2023/3/15 21:27
 */
public class KryoSerializer implements Serializer {

    private final ThreadLocal<Kryo> kryoHolder = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        kryo.register(RpcResponse.class);
        kryo.register(RpcRequest.class);
        return kryo;
    });

    @Override
    public byte[] serialize(Object obj) {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             Output output = new Output(out)) {
            kryoHolder.get().writeObject(output, obj);
            kryoHolder.remove();
            return output.toBytes();
        } catch (Exception e) {
            throw new SerializeException("serialize failed: " + e.getMessage(), e);
        }
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> clazz) {
        try (ByteArrayInputStream in = new ByteArrayInputStream(bytes);
             Input input = new Input(in)) {
            Object obj = kryoHolder.get().readObject(input, clazz);
            kryoHolder.remove();
            return clazz.cast(obj);
        } catch (Exception e) {
            throw new SerializeException("deserialize failed: " + e.getMessage(), e);
        }
    }

}
